/*
* @Author: z.p
* @Project: Zdotp
* @Date: 2025年01月18日
* @Description: 网络包管理器文件
*/

using System.Reflection;
using Google.Protobuf;
using Zdotp.Actor.Kcp;
using Zdotp.Logs;

namespace Zdotp.Net.NetMessageHandler;

public static class KcpNetHandlerManager
{
    private static readonly ZLogger Logger = new("KcpNetHandlerManager");
    private static readonly Dictionary<Type, IMessageHandler> MessageHandlers = new();
    private static readonly Dictionary<Type, object?> Parsers = new();
    private static readonly Lock Lock = new();
    
    private static readonly Dictionary<uint, Type> ProtocolId2MessageType = new();
    private static readonly Dictionary<Type, uint> MessageType2ProtocolId = new();

    public static void LoadAssemblies(List<Assembly> assemblies)
    {
        List<Type> types = new();
        foreach (var assembly in assemblies)
        {
            foreach (var classType in assembly.GetTypes())
            {
                AddHandler(classType);
                AddMessage(types, classType);
            }
        }
        
        types.Sort((x, y) => string.CompareOrdinal(x.Name, y.Name));

        var index = 0u;
        foreach (var type in types)
        {
            ++index;
            MessageType2ProtocolId.Add(type, index);
            ProtocolId2MessageType.Add(index, type);
            Logger.Info($"register handler [ protocolId: {index}, messageType: {type.Name} ]");
            
            var parserProperty = type.GetProperty("Parser", BindingFlags.Public | BindingFlags.Static);
            var value = parserProperty?.GetValue(null);
            AddParser(type, value);
        }
    }

    private static void AddHandler(Type classType)
    {
        var baseType = classType.BaseType;
        if (baseType == null) return;
        if (!baseType.IsGenericType || baseType.GetGenericTypeDefinition() != typeof(KcpMessageHandler<>)) return;
        var genericArguments = baseType.GetGenericArguments();
        if (genericArguments.Length != 1) return;
        var messageType = genericArguments[0];
        var messageHandler = Activator.CreateInstance(classType);
                
        if (messageHandler is not IMessageHandler iHandler)
        {
            Logger.Error($"Load interface {classType.Name} failed.");
            return;
        }
        if (!MessageHandlers.TryAdd(messageType, iHandler))
        {
            Logger.Error($"MessageType {messageType} allows only one netHandler to exist.");
            return;
        }
    }

    private static void AddMessage(List<Type> types, Type classType)
    {
        var interfaces = classType.GetInterfaces();
        if (interfaces.Length == 0) return;
        foreach (var interfaceType in interfaces)
        {
            if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IMessage<>))
            {
                var genericArguments = interfaceType.GetGenericArguments();
                if (genericArguments.Length != 1) continue;
                var messageType = genericArguments[0];
                types.Add(messageType);
                break;
            }
        }
    }
    
    public static void Handle(uint protocolId, ActorKcp actor, uint sessionId, byte[] message)
    {
        if (!ProtocolId2MessageType.TryGetValue(protocolId, out var messageType))
        {
            Logger.Error($"MessageType {protocolId} not found.");
            return;
        }
        if (!MessageHandlers.TryGetValue(messageType, out var handler))
        {
            Logger.Error($"Handler {messageType} not found.");
            return;
        }
        handler.Handle(actor, sessionId, message);
    }
    public static uint GetProtocolId(Type messageType)
    {
        if (!MessageType2ProtocolId.TryGetValue(messageType, out var protocolId))
        {
            Logger.Error($"MessageType {messageType} not found.");
            return 0;
        }
        return protocolId;
    }

    public static void AddParser(Type type, object? parser)
    {
        lock (Lock)
        {
            Parsers.TryAdd(type, parser);
        }
    }

    public static MessageParser<T>? GetParser<T>() where T : IMessage<T>
    {
        object? parser;
        lock (Lock)
        {
            Parsers.TryGetValue(typeof(T), out parser);
        }
        if (parser is MessageParser<T> res) return res;
        Logger.Error($"Parser {typeof(T)} is not MessageParser.");
        return null;
    }
}
